home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / util / misc / MUser17src.lha / MultiUser / src / Library / Server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-07  |  17.2 KB  |  783 lines

  1. /************************************************************
  2. * MultiUser - MultiUser Task/File Support System                *
  3. * ---------------------------------------------------------    *
  4. * Server Process                                                            *
  5. * ---------------------------------------------------------    *
  6. * © Copyright 1993-1994 Geert Uytterhoeven                        *
  7. * All Rights Reserved.                                                    *
  8. ************************************************************/
  9.  
  10.  
  11. #include <exec/execbase.h>
  12. #include <exec/alerts.h>
  13. #include <exec/ports.h>
  14. #include <dos/dos.h>
  15. #include <dos/dostags.h>
  16. #include <utility/tagitem.h>
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/utility.h>
  20. #include <proto/reqtools.h>
  21. #include <libraries/reqtools.h>
  22. #include <string.h>
  23.  
  24. #include "Memory.h"
  25. #include "Server.h"
  26. #include "Config.h"
  27. #include "LibHeader.h"
  28. #include "Misc.h"
  29. #include "Task.h"
  30. #include "UserInfo.h"
  31. #include "GroupInfo.h"
  32. #include "Monitor.h"
  33.  
  34.  
  35.     /*
  36.      *        Static Routines
  37.      */
  38.  
  39. static void __saveds ServerProcess(void);
  40. static struct muPrivUserInfo *CheckUser(ULONG user, STRPTR userid, STRPTR pwd, BOOL nopasswd,
  41.                                                      BOOL nolog);
  42. static BOOL Passwd(ULONG user, STRPTR oldpwd, STRPTR newpwd);
  43. static struct muPrivUserInfo *GetUserInfo(struct muPrivUserInfo *info, ULONG keytype);
  44. static BOOL Belongs2(struct muUserDef *def, UWORD gid);
  45. static void FillUserInfo(struct muUserDef *def, struct muPrivUserInfo *info);
  46. static BOOL CheckPasswd(ULONG user, STRPTR pwd);
  47. static struct muPrivGroupInfo *GetGroupInfo(struct muPrivGroupInfo *info, ULONG keytype);
  48. static void FillGroupInfo(struct muGroupDef *def, struct muPrivGroupInfo *info);
  49.  
  50.  
  51.     /*
  52.      *        Configuration Stuff
  53.      */
  54.  
  55. extern BPTR PasswdDirLock;
  56. extern BPTR ConfigDirLock;
  57.  
  58.  
  59.     /*
  60.      *        Start the Server's Process
  61.      */
  62.  
  63. struct Process *CreateServer(void)
  64. {
  65.     static struct TagItem tags[] = {
  66.         NP_Entry, (LONG)ServerProcess,
  67.         NP_Name, (LONG)SERVERNAME,
  68.         NP_Priority, SERVERPRI,
  69.         NP_StackSize, SERVERSTACK,
  70.         TAG_DONE
  71.     };
  72.  
  73.     return(muBase->Server = CreateNewProc((struct TagItem *)tags));
  74.  
  75. }
  76.  
  77.  
  78.     /*
  79.      *        Activate the Server by sending the Startup Message
  80.      */
  81.  
  82. BOOL StartServer(void)
  83. {
  84.     return((BOOL)DoPkt(&muBase->Server->pr_MsgPort, ACTION_STARTUP, NULL, NULL, NULL, NULL, NULL));
  85. }
  86.  
  87.  
  88.     /*
  89.      *        Kill the Server
  90.      */
  91.  
  92. BOOL KillServer(void)
  93. {
  94.     return((BOOL)SendServerPacket(muSAction_Quit, NULL, NULL, NULL, NULL));
  95. }
  96.  
  97.  
  98.     /*
  99.      *        Send a Packet to the Server
  100.      */
  101.  
  102. LONG SendServerPacket(LONG type, LONG arg1, LONG arg2, LONG arg3, LONG arg4)
  103. {
  104.     struct muSPacket pkt;
  105.     struct MsgPort *port;
  106.  
  107.     if (port = CreateMsgPort()) {
  108.  
  109.             /*
  110.              *        Initialise the Server Packet
  111.              */
  112.  
  113.         pkt.Msg.mn_Node.ln_Succ = NULL;
  114.         pkt.Msg.mn_Node.ln_Pred = NULL;
  115.         pkt.Msg.mn_Node.ln_Type = NULL;
  116.         pkt.Msg.mn_Node.ln_Pri = NULL;
  117.         pkt.Msg.mn_Node.ln_Name = NULL;
  118.         pkt.Msg.mn_ReplyPort = port;
  119.         pkt.Msg.mn_Length = sizeof(struct muSPacket);
  120.         pkt.Type = type;
  121.         pkt.Arg1 = arg1;
  122.         pkt.Arg2 = arg2;
  123.         pkt.Arg3 = arg3;
  124.         pkt.Arg4 = arg4;
  125.         pkt.Res1 = NULL;
  126.  
  127.             /*
  128.              *        Transmit the packet and wait for reply
  129.              */
  130.  
  131.         Forbid();
  132.         if (muBase->ServerPort) {
  133.             PutMsg(muBase->ServerPort, (struct Message *)&pkt);
  134.             Permit();
  135.             do
  136.                 WaitPort(port);
  137.             while (GetMsg(port) != (struct Message *)&pkt);
  138.         } else
  139.             Permit();
  140.  
  141.         DeleteMsgPort(port);
  142.         return(pkt.Res1);
  143.     } else
  144.         return(NULL);
  145. }
  146.  
  147.  
  148.     /*
  149.      *        The Server's Process
  150.      */
  151.  
  152. static void __saveds ServerProcess(void)
  153. {
  154.     struct muSPacket *pkt;
  155.     BOOL quit = FALSE;
  156.     ULONG user;
  157.     ULONG signals;
  158.     struct DosPacket *spkt;
  159.  
  160.         /*
  161.          *        Get Startup Message
  162.          */
  163.  
  164.     spkt = WaitPkt();
  165.  
  166.         /*
  167.          *        Do all necessary initialisations
  168.          */
  169.  
  170.     ((struct Process *)SysBase->ThisTask)->pr_WindowPtr = (APTR)-1;
  171.  
  172.     if (((muBase->NotifySig = AllocSignal(-1)) == -1) ||
  173.          ((muBase->ConsistencySig = AllocSignal(-1)) == -1) || !(muBase->ServerPort = CreateMsgPort()) ||
  174.          !(muBase->MonitorPort = CreateMsgPort())) {
  175.         ReplyPkt(spkt, DOSFALSE, NULL);
  176.         Die(NULL, AN_Unknown | AG_NoSignal);
  177.     }
  178.  
  179.         /*
  180.          *        Reply Startup Message
  181.          */
  182.  
  183.     ReplyPkt(spkt, DOSTRUE, NULL);
  184.  
  185.     InitVolumes();
  186.  
  187.     do {
  188.         signals = Wait(1<<muBase->NotifySig | 1<<muBase->ConsistencySig |
  189.                             1<<muBase->ServerPort->mp_SigBit | 1<<muBase->MonitorPort->mp_SigBit);
  190.  
  191.         if (signals & 1<<muBase->NotifySig)
  192.             FreeDefs();
  193.  
  194.         if (signals & 1<<muBase->ConsistencySig) {
  195.             FreeVolumes();
  196.             InitVolumes();
  197.         }
  198.  
  199.         if (signals & 1<<muBase->ServerPort->mp_SigBit)
  200.             while (!quit && (pkt = (struct muSPacket *)GetMsg(muBase->ServerPort))) {
  201.                 switch (pkt->Type) {
  202.                     case muSAction_Quit:
  203.  
  204.                             /*
  205.                              *        Quit
  206.                              *
  207.                              *
  208.                              *        Arg1:    /
  209.                              *        Arg2:    /
  210.                              *        Arg3:    /
  211.                              *
  212.                              *        Res1:    BOOL success
  213.                              */
  214.  
  215.                         quit = TRUE;
  216.                         pkt->Res1 = TRUE;
  217.  
  218.                             /*
  219.                              *        Ensure the Server will be RemTask()ed BEFORE any
  220.                              *        other task will get the processor !!
  221.                              */
  222.  
  223.                         Forbid();
  224.                         break;
  225.  
  226.                     case muSAction_CheckUser:
  227.  
  228.                             /*
  229.                              *        CheckUser
  230.                              *
  231.                              *
  232.                              *        Arg1:    STRPTR uid
  233.                              *        Arg2:    STRPTR pwd
  234.                              *        Arg3:    BOOL nopasswd
  235.                              *
  236.                              *        Res1:    struct muPrivUserInfo *info (NULL for failure)
  237.                              */
  238.  
  239.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  240.                         pkt->Res1 = (LONG)CheckUser(user, (STRPTR)pkt->Arg1, (STRPTR)pkt->Arg2,
  241.                                                              (BOOL)pkt->Arg3, (BOOL)pkt->Arg4);
  242.                         break;
  243.  
  244.                     case muSAction_Passwd:
  245.  
  246.                             /*
  247.                              *        Passwd
  248.                              *
  249.                              *
  250.                              *        Arg1:    STRPTR oldpwd
  251.                              *        Arg2:    STRPTR newpwd
  252.                              *        Arg3:    /
  253.                              *
  254.                              *        Res1:    BOOL success
  255.                              */
  256.  
  257.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  258.                         pkt->Res1 = (LONG)Passwd(user, (STRPTR)pkt->Arg1, (STRPTR)pkt->Arg2);
  259.                         break;
  260.  
  261.                     case muSAction_GetUserInfo:
  262.  
  263.                             /*
  264.                              *        GetUserInfo
  265.                              *
  266.                              *
  267.                              *        Arg1:    struct muPrivUserInfo *info
  268.                              *        Arg2:    ULONG keytype
  269.                              *        Arg3:    /
  270.                              *
  271.                              *        Res1:    struct muPrivUserInfo *info (NULL for failure)
  272.                              */
  273.  
  274.                         pkt->Res1 = (LONG)GetUserInfo((struct muPrivUserInfo *)pkt->Arg1, (ULONG)pkt->Arg2);
  275.                         break;
  276.  
  277.                     case muSAction_CheckPasswd:
  278.  
  279.                             /*
  280.                              *        CheckPasswd
  281.                              *
  282.                              *
  283.                              *        Arg1:    STRPTR pwd
  284.                              *        Arg2:    /
  285.                              *        Arg3:    /
  286.                              *
  287.                              *        Res1:    BOOL success
  288.                              */
  289.  
  290.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  291.                         pkt->Res1 = (LONG)CheckPasswd(user, (STRPTR)pkt->Arg1);
  292.                         break;
  293.  
  294.                     case muSAction_PasswdDirLock:
  295.  
  296.                             /*        PasswdDirLock
  297.                              *
  298.                              *
  299.                              *        Arg1:    /
  300.                              *        Arg2:    /
  301.                              *        Arg3:    /
  302.                              *
  303.                              *        Res1:    BPTR lock
  304.                              */
  305.  
  306.                         if (PasswdDirLock)
  307.                             pkt->Res1 = DupLock(PasswdDirLock);
  308.                         break;
  309.  
  310.                     case muSAction_ConfigDirLock:
  311.  
  312.                             /*        ConfigDirLock
  313.                              *
  314.                              *
  315.                              *        Arg1:    /
  316.                              *        Arg2:    /
  317.                              *        Arg3:    /
  318.                              *
  319.                              *        Res1:    BPTR lock
  320.                              */
  321.  
  322.                         if (ConfigDirLock)
  323.                             pkt->Res1 = DupLock(ConfigDirLock);
  324.                         break;
  325.  
  326.                     case muSAction_GetGroupInfo:
  327.  
  328.                             /*
  329.                              *        GetGroupInfo
  330.                              *
  331.                              *
  332.                              *        Arg1:    struct muPrivGroupInfo *info
  333.                              *        Arg2:    ULONG keytype
  334.                              *        Arg3:    /
  335.                              *
  336.                              *        Res1:    struct muPrivGroupInfo *info (NULL for failure)
  337.                              */
  338.  
  339.                         pkt->Res1 = (LONG)GetGroupInfo((struct muPrivGroupInfo *)pkt->Arg1, (ULONG)pkt->Arg2);
  340.                         break;
  341.  
  342.                     default:
  343.                         break;
  344.                 }
  345.             ReplyMsg((struct Message *)pkt);
  346.             }
  347.  
  348.         if (signals & 1<<muBase->MonitorPort->mp_SigBit)
  349.             FreeRepliedMonMsg();
  350.  
  351.     } while (!quit);
  352.  
  353.     FreeVolumes();
  354.  
  355.     DeleteMsgPort(muBase->MonitorPort);
  356.     DeleteMsgPort(muBase->ServerPort);
  357.     FreeSignal(muBase->ConsistencySig);
  358.     FreeSignal(muBase->NotifySig);
  359.     muBase->MonitorPort = NULL;
  360.     muBase->ServerPort = NULL;
  361.     muBase->ConsistencySig = NULL;
  362.     muBase->Server = NULL;
  363. }
  364.  
  365.  
  366.     /*
  367.      *        Check if a user is licensed to login
  368.      */
  369.  
  370. static struct muPrivUserInfo *CheckUser(ULONG user, STRPTR userid, STRPTR pwd, BOOL nopasswd,
  371.                                                      BOOL nolog)
  372. {
  373.     BOOL found;
  374.     char buffer[12];
  375.     struct muPrivUserInfo *info = NULL;
  376.     struct muUserDef *def;
  377.     UWORD uid;
  378.  
  379.     uid = user>>16;
  380.  
  381.     if (def = GetUserDefs())
  382.         do
  383.             if ((found = (!strcmp(userid, def->UserID))) && (nopasswd ||
  384.                  (Encrypt(buffer, pwd, def->UserID) && !strcmp(buffer, def->Password))) &&
  385.                   (info = muAllocUserInfo()))
  386.                 FillUserInfo(def, info);
  387.             else
  388.                 def = def->Next;
  389.         while (!found && def);
  390.  
  391.     if (info)
  392.         CallMonitors(muTrgB_Login, uid, info->Pub.uid, userid);
  393.     else
  394.         CallMonitors(muTrgB_LoginFail, uid, NULL, userid);
  395.  
  396.     if (!nolog && ((info && (muBase->Config.LogFlags & muLogF_Login)) ||
  397.                         (!info && (muBase->Config.LogFlags & muLogF_LoginFail)))) {
  398.         LONG args[2];
  399.         args[0] = uid;
  400.         args[1] = (LONG)userid;
  401.         if (info)
  402.             VLogF("Login from %ld to '%s'", args);
  403.         else
  404.             VLogF("Login from %ld to '%s' failed", args);
  405.     }
  406.  
  407.     return(info);
  408. }
  409.  
  410.  
  411.     /*
  412.      *        Change the Password of a user
  413.      */
  414.  
  415. static BOOL Passwd(ULONG user, STRPTR oldpwd, STRPTR newpwd)
  416. {
  417.     BOOL found;
  418.     BOOL changed = FALSE;
  419.     UWORD uid, gid;
  420.     char buffer[12];
  421.     struct muUserDef *def;
  422.  
  423.     uid = user>>16;
  424.     gid = user&muMASK_GID;
  425.  
  426.     if (((uid >= muBase->Config.PasswduidLevel) || (gid >= muBase->Config.PasswdgidLevel)) &&
  427.          (def = GetUserDefs()))
  428.         do
  429.             if (found = (def->uid == uid))
  430.                 changed = Encrypt(buffer, oldpwd, def->UserID) &&  !strcmp(buffer, def->Password) &&
  431.                              Encrypt(def->Password, newpwd, def->UserID) && UpdateUserDefs();
  432.             else
  433.                 def = def->Next;
  434.         while (!found && def);
  435.  
  436.     if (changed)
  437.         CallMonitors(muTrgB_Passwd, uid, NULL, NULL);
  438.     else
  439.         CallMonitors(muTrgB_PasswdFail, uid, NULL, NULL);
  440.  
  441.     if ((changed && (muBase->Config.LogFlags & muLogF_Passwd)) ||
  442.          (!changed && (muBase->Config.LogFlags & muLogF_PasswdFail))) {
  443.         LONG args[1];
  444.         args[0] = uid;
  445.         if (changed)
  446.             VLogF("Passwd for %ld", args);
  447.         else
  448.             VLogF("Passwd for %ld failed", args);
  449.     }
  450.  
  451.     return(changed);
  452. }
  453.  
  454.  
  455.     /*
  456.      *        Get Information about a User
  457.      */
  458.  
  459. static struct muPrivUserInfo *GetUserInfo(struct muPrivUserInfo *info, ULONG keytype)
  460. {
  461.     struct muUserDef *def;
  462.     ULONG len;
  463.     ULONG count = 0;
  464.  
  465.     if (def = GetUserDefs()) {
  466.         switch (keytype) {
  467.             case muKeyType_First:
  468.                 break;
  469.  
  470.             case muKeyType_Next:
  471.                 while ((count <= info->Count) && (def = def->Next))
  472.                     count++;
  473.                 break;
  474.  
  475.             case muKeyType_UserID:
  476.                 while (strcmp(def->UserID, info->Pub.UserID) && (def = def->Next))
  477.                     count++;
  478.                 break;
  479.  
  480.             case muKeyType_uid:
  481.                 while ((def->uid != info->Pub.uid) && (def = def->Next))
  482.                     count++;
  483.                 break;
  484.  
  485.             case muKeyType_gid:
  486.                 info->Tgid = info->Pub.gid;
  487.                 while (!Belongs2(def, info->Tgid) && (def = def->Next))
  488.                     count++;
  489.                 break;
  490.  
  491.             case muKeyType_gidNext:
  492.                 while ((count <= info->Count) && (def = def->Next))
  493.                     count++;
  494.                 if (def)
  495.                     while (!Belongs2(def, info->Tgid) && (def = def->Next))
  496.                         count++;
  497.                 break;
  498.  
  499.             case muKeyType_UserName:
  500.                 while (stricmp(def->UserName, info->Pub.UserName) && (def = def->Next))
  501.                     count++;
  502.                 break;
  503.  
  504.             case muKeyType_WUserID:
  505.                 FreeV(info->Pattern);
  506.                 len = 2*strlen(info->Pub.UserID)+2;
  507.                 if ((info->Pattern = MAllocV(len)) &&
  508.                      (ParsePatternNoCase(info->Pub.UserID, info->Pattern, len) != -1))
  509.                     while (!MatchPatternNoCase(info->Pattern, def->UserID) && (def = def->Next))
  510.                         count++;
  511.                 else {
  512.                     FreeV(info->Pattern);
  513.                     info->Pattern = NULL;
  514.                     def = NULL;
  515.                 }
  516.                 break;
  517.  
  518.             case muKeyType_WUserIDNext:
  519.                 if (info->Pattern) {
  520.                     while ((count <= info->Count) && (def = def->Next))
  521.                         count++;
  522.                     if (def)
  523.                         while (!MatchPatternNoCase(info->Pattern, def->UserID) && (def = def->Next))
  524.                             count++;
  525.                 } else
  526.                     def = NULL;
  527.                 break;
  528.  
  529.             case muKeyType_WUserName:
  530.                 FreeV(info->Pattern);
  531.                 len = 2*strlen(info->Pub.UserName)+2;
  532.                 if ((info->Pattern = MAllocV(len)) &&
  533.                      (ParsePatternNoCase(info->Pub.UserName, info->Pattern, len) != -1))
  534.                     while (!MatchPatternNoCase(info->Pattern, def->UserName) && (def = def->Next))
  535.                         count++;
  536.                 else {
  537.                     FreeV(info->Pattern);
  538.                     info->Pattern = NULL;
  539.                     def = NULL;
  540.                 }
  541.                 break;
  542.  
  543.             case muKeyType_WUserNameNext:
  544.                 if (info->Pattern) {
  545.                     while ((count <= info->Count) && (def = def->Next))
  546.                         count++;
  547.                     if (def)
  548.                         while (!MatchPatternNoCase(info->Pattern, def->UserName) && (def = def->Next))
  549.                             count++;
  550.                 } else
  551.                     def = NULL;
  552.                 break;
  553.  
  554.             default:
  555.                 def = NULL;
  556.                 break;
  557.         }
  558.         if (def) {
  559.             FillUserInfo(def, info);
  560.             info->Count = count;
  561.         } else
  562.             info = NULL;
  563.     } else
  564.         info = NULL;
  565.  
  566.     return(info);
  567. }
  568.  
  569.  
  570.     /*
  571.      *        Checker whether a user belongs to a group
  572.      */
  573.  
  574. static BOOL Belongs2(struct muUserDef *def, UWORD gid)
  575. {
  576.     int i;
  577.  
  578.     if (def->gid == gid)
  579.         return(TRUE);
  580.     for (i = 0; i < def->NumSecGroups; i++)
  581.         if (def->SecGroups[i] == gid)
  582.             return(TRUE);
  583.     return(FALSE);
  584. }
  585.  
  586.  
  587.     /*
  588.      *        Fill in the User Information
  589.      */
  590.  
  591. static void FillUserInfo(struct muUserDef *def, struct muPrivUserInfo *info)
  592. {
  593.     strncpy(info->Pub.UserID, def->UserID, muUSERIDSIZE-1);
  594.     info->Pub.UserID[muUSERIDSIZE-1] = '\0';
  595.     info->Pub.uid = def->uid;
  596.     info->Pub.gid = def->gid;
  597.     strncpy(info->Pub.UserName, def->UserName, muUSERNAMESIZE-1);
  598.     info->Pub.UserName[muUSERNAMESIZE-1] = '\0';
  599.     strncpy(info->Pub.HomeDir, def->HomeDir, muHOMEDIRSIZE-1);
  600.     info->Pub.HomeDir[muHOMEDIRSIZE-1] = '\0';
  601.     if (info->Pub.NumSecGroups)
  602.        Free(info->Pub.SecGroups, info->Pub.NumSecGroups*sizeof(UWORD));
  603.     if (def->NumSecGroups && (info->Pub.SecGroups = MAlloc(def->NumSecGroups*sizeof(UWORD)))) {
  604.         info->Pub.NumSecGroups = def->NumSecGroups;
  605.         CopyMem(def->SecGroups, info->Pub.SecGroups, def->NumSecGroups*sizeof(UWORD));
  606.     } else {
  607.         info->Pub.NumSecGroups = 0;
  608.         info->Pub.SecGroups = NULL;
  609.     }
  610.     strncpy(info->Pub.Shell, def->Shell, muSHELLSIZE-1);
  611.     info->Password = !!strlen(def->Password);
  612. }
  613.  
  614.  
  615.     /*
  616.      *        Check the Password of a User
  617.      */
  618.  
  619. static BOOL CheckPasswd(ULONG user, STRPTR pwd)
  620. {
  621.     BOOL found;
  622.     BOOL valid = FALSE;
  623.     UWORD uid;
  624.     char buffer[12];
  625.     struct muUserDef *def;
  626.  
  627.     uid = user>>16;
  628.  
  629.     if (def = GetUserDefs())
  630.         do
  631.             if (found = (def->uid == uid))
  632.                 valid = Encrypt(buffer, pwd, def->UserID) && !strcmp(buffer, def->Password);
  633.             else
  634.                 def = def->Next;
  635.         while (!found && def);
  636.  
  637.     if (valid)
  638.         CallMonitors(muTrgB_CheckPasswd, uid, NULL, NULL);
  639.     else
  640.         CallMonitors(muTrgB_CheckPasswdFail, uid, NULL, NULL);
  641.  
  642.     if ((valid && (muBase->Config.LogFlags & muLogF_CheckPasswd)) ||
  643.          (!valid && (muBase->Config.LogFlags & muLogF_CheckPasswdFail))) {
  644.         LONG args[1];
  645.         args[0] = uid;
  646.         if (valid)
  647.             VLogF("CheckPasswd for %ld", args);
  648.         else
  649.             VLogF("CheckPasswd for %ld failed", args);
  650.     }
  651.  
  652.     return(valid);
  653. }
  654.  
  655.  
  656.     /*
  657.      *        Get Information about a Group
  658.      */
  659.  
  660. static struct muPrivGroupInfo *GetGroupInfo(struct muPrivGroupInfo *info, ULONG keytype)
  661. {
  662.     struct muGroupDef *def;
  663.     ULONG len;
  664.     ULONG count = 0;
  665.  
  666.     if (def = GetGroupDefs()) {
  667.         switch (keytype) {
  668.             case muKeyType_First:
  669.                 break;
  670.  
  671.             case muKeyType_Next:
  672.                 while ((count <= info->Count) && (def = def->Next))
  673.                     count++;
  674.                 break;
  675.  
  676.             case muKeyType_GroupID:
  677.                 while (strcmp(def->GroupID, info->Pub.GroupID) && (def = def->Next))
  678.                     count++;
  679.                 break;
  680.  
  681.             case muKeyType_gid:
  682.                 while ((def->gid != info->Pub.gid) && (def = def->Next))
  683.                     count++;
  684.                 break;
  685.  
  686.             case muKeyType_GroupName:
  687.                 while (stricmp(def->GroupName, info->Pub.GroupName) && (def = def->Next))
  688.                     count++;
  689.                 break;
  690.  
  691.             case muKeyType_WGroupID:
  692.                 FreeV(info->Pattern);
  693.                 len = 2*strlen(info->Pub.GroupID)+2;
  694.                 if ((info->Pattern = MAllocV(len)) &&
  695.                      (ParsePatternNoCase(info->Pub.GroupID, info->Pattern, len) != -1))
  696.                     while (!MatchPatternNoCase(info->Pattern, def->GroupID) && (def = def->Next))
  697.                         count++;
  698.                 else {
  699.                     FreeV(info->Pattern);
  700.                     info->Pattern = NULL;
  701.                     def = NULL;
  702.                 }
  703.                 break;
  704.  
  705.             case muKeyType_WGroupIDNext:
  706.                 if (info->Pattern) {
  707.                     while ((count <= info->Count) && (def = def->Next))
  708.                         count++;
  709.                     if (def)
  710.                         while (!MatchPatternNoCase(info->Pattern, def->GroupID) && (def = def->Next))
  711.                             count++;
  712.                 } else
  713.                     def = NULL;
  714.                 break;
  715.  
  716.             case muKeyType_WGroupName:
  717.                 FreeV(info->Pattern);
  718.                 len = 2*strlen(info->Pub.GroupName)+2;
  719.                 if ((info->Pattern = MAllocV(len)) &&
  720.                      (ParsePatternNoCase(info->Pub.GroupName, info->Pattern, len) != -1))
  721.                     while (!MatchPatternNoCase(info->Pattern, def->GroupName) && (def = def->Next))
  722.                         count++;
  723.                 else {
  724.                     FreeV(info->Pattern);
  725.                     info->Pattern = NULL;
  726.                     def = NULL;
  727.                 }
  728.                 break;
  729.  
  730.             case muKeyType_WGroupNameNext:
  731.                 if (info->Pattern) {
  732.                     while ((count <= info->Count) && (def = def->Next))
  733.                         count++;
  734.                     if (def)
  735.                         while (!MatchPatternNoCase(info->Pattern, def->GroupName) && (def = def->Next))
  736.                             count++;
  737.                 } else
  738.                     def = NULL;
  739.                 break;
  740.  
  741.             case muKeyType_MgrUid:
  742.                 while ((def->MgrUid != info->Pub.MgrUid) && (def = def->Next))
  743.                     count++;
  744.                 break;
  745.  
  746.             case muKeyType_MgrUidNext:
  747.                 while ((count <= info->Count) && (def = def->Next))
  748.                     count++;
  749.                 if (def)
  750.                     while ((def->MgrUid != info->Pub.MgrUid) && (def = def->Next))
  751.                         count++;
  752.                 break;
  753.  
  754.             default:
  755.                 def = NULL;
  756.                 break;
  757.         }
  758.         if (def) {
  759.             FillGroupInfo(def, info);
  760.             info->Count = count;
  761.         } else
  762.             info = NULL;
  763.     } else
  764.         info = NULL;
  765.  
  766.     return(info);
  767. }
  768.  
  769.  
  770.     /*
  771.      *        Fill in the Group Information
  772.      */
  773.  
  774. static void FillGroupInfo(struct muGroupDef *def, struct muPrivGroupInfo *info)
  775. {
  776.     strncpy(info->Pub.GroupID, def->GroupID, muGROUPIDSIZE-1);
  777.     info->Pub.GroupID[muGROUPIDSIZE-1] = '\0';
  778.     info->Pub.gid = def->gid;
  779.     info->Pub.MgrUid = def->MgrUid;
  780.     strncpy(info->Pub.GroupName, def->GroupName, muGROUPNAMESIZE-1);
  781.     info->Pub.GroupName[muGROUPNAMESIZE-1] = '\0';
  782. }
  783.